home *** CD-ROM | disk | FTP | other *** search
/ Celestin Apprentice 5 / Apprentice-Release5.iso / Source Code / Pascal / Applications / NIH Image 1.60 / 1.60 Source / Lut.p < prev    next >
Encoding:
Text File  |  1996-03-01  |  52.1 KB  |  2,213 lines  |  [TEXT/PJMM]

  1. unit Lut;
  2. {This file contains routines that deal with the video Look-Up Table(LUT).}
  3.  
  4. interface
  5.  
  6.     uses
  7.         TYpes, Memory, QuickDraw, QuickDrawText, Packages, Menus, Events, Fonts, Scrap, ToolUtils,
  8.         Resources, Palettes, Printing, ColorPicker, Windows, Files, globals, Utilities, Graphics,
  9.         Dialogs;
  10.  
  11.     function GetPseudoColorIndex: integer;
  12.     function isGrayScaleLUT: boolean;
  13.     procedure DoMouseDownInLUT (event: EventRecord);
  14.     procedure DoCopyColor;
  15.     procedure PasteColor;
  16.     procedure ShowRGBValues (index: integer);
  17.     procedure InvertPalette;
  18.     procedure FindPoints (var x1, y1, x2, y2: integer);
  19.     procedure UpdateMap;
  20.     procedure ResetGraymap;
  21.     procedure DrawMap;
  22.     procedure DoMouseDownInMap;
  23.     procedure EnableThresholding (level: integer);
  24.     procedure DisableThresholding;
  25.     procedure DrawLUT;
  26.     procedure UpdateLUT;
  27.     procedure LoadColorTable (theColorTable: CTabHandle);
  28.     function LoadCLUTResource (id: integer): boolean;
  29.     procedure GetLookupTable (var table: LookupTable);
  30.     procedure RedrawLUTWindow;
  31.     procedure DrawDensitySlice (OptionKey: boolean);
  32.     procedure SelectLutTool;
  33.     procedure EnableDensitySlice;
  34.     procedure SetupPseudocolor;
  35.     procedure DoImportLut (fname: str255; vnum: integer);
  36.     procedure OpenOldPalette (fname: str255; RefNum: integer);
  37.     procedure OpenNewPalette (fname: str255; RefNum: integer);
  38.     procedure OpenColorTable (fname: str255; RefNum: integer);
  39.     procedure ImportPalette (FileType: OSType; fname: str255; vnum: integer);
  40.     procedure GetColorTable (id: integer);
  41.     procedure GetLutResource (id: integer);
  42.     procedure DrawScale;
  43.     procedure MakeSpectrum;
  44.     function GetColorTableItem (ctab: ColorTableType): integer;
  45.     procedure SwitchColorTables (item: integer; update: boolean);
  46.     procedure InitPaletteHeader (var hdr: PaletteHeader);
  47.     procedure ResetMap;
  48.     procedure DoLutOptions;
  49.     function SetupMask: boolean;
  50.     procedure PutLineUsingMask (h, v, count: integer; var line: LineType);
  51.     procedure ApplyTable (var table: LookupTable);
  52.     procedure FixColors;
  53.  
  54.  
  55.  
  56. implementation
  57.  
  58.  
  59.     function GetPseudoColorIndex: integer;
  60.         var
  61.             index: integer;
  62.     begin
  63.         with info^ do begin
  64.                 index := trunc((nColors) * (ForegroundIndex - ColorStart) / (ColorEnd - ColorStart + 1));
  65.                 if index < 0 then
  66.                     index := 0;
  67.                 if index > (nColors - 1) then
  68.                     index := nColors - 1;
  69.                 GetPseudoColorIndex := index;
  70.             end;
  71.     end;
  72.  
  73.  
  74.     procedure UpdateLUT;
  75.         var
  76.             MaxStart, i, v, index, last: integer;
  77.             inc, sIndex: LongInt;
  78.     begin
  79.         with info^ do begin
  80.                 sIndex := 0;
  81.                 if ColorEnd > ColorStart then
  82.                     inc := nColors * 10000 div (ColorEnd - ColorStart)
  83.                 else
  84.                     inc := 2560000;
  85.                 if ColorStart < 0 then
  86.                     sIndex := -ColorStart * Inc
  87.                 else
  88.                     sIndex := 0;
  89.                 last := nColors - 1;
  90.                 for i := 0 to 255 do
  91.                     with cTable[i].rgb do begin
  92.                             if (i < ColorStart) or (i > ColorEnd) then begin
  93.                                     if i < ColorStart then
  94.                                         cTable[i].rgb := FillColor1
  95.                                     else
  96.                                         cTable[i].rgb := FillColor2;
  97.                                 end
  98.                             else begin
  99.                                     index := sIndex div 10000;
  100.                                     if index > last then
  101.                                         index := last;
  102.                                     Red := bsl(band(RedLUT[index],255), 8);
  103.                                     Green := bsl(band(GreenLUT[index],255), 8);
  104.                                     Blue := bsl(band(BlueLUT[index],255), 8);
  105.                                     sIndex := sIndex + inc;
  106.                                 end;
  107.                         end; {for}
  108.                 if ColorStart = ColorEnd then
  109.                     cTable[ColorStart].rgb := FillColor2
  110.                 else
  111.                     Thresholding := false;
  112.                 LoadLUT(cTable);
  113.                 IdentityFunction := false;
  114.             end;
  115.     end;
  116.  
  117.  
  118.     function GetVLoc: integer;
  119.         var
  120.             loc: point;
  121.             vloc: integer;
  122.     begin
  123.         GetMouse(loc);
  124.         vloc := loc.v;
  125.         if vloc > 255 then
  126.             vloc := 255;
  127.         if vloc <= 0 then
  128.             vloc := 0;
  129.         GetVLoc := vloc;
  130.     end;
  131.  
  132.  
  133.     procedure GetNewColor (var color: RGBColor);
  134.         var
  135.             where: point;
  136.             inRGBColor, OutRGBColor: RGBColor;
  137.     begin
  138.         inRGBColor := color;
  139.         outRGBColor := color;
  140.         where.h := 0;
  141.         where.v := 0;
  142.         InitCursor;
  143.         if GetColor(where, 'Pick a new color...', inRGBColor, outRGBColor) then
  144.             color := outRGBColor;
  145.     end;
  146.  
  147.  
  148.     procedure EditPseudoColors;
  149.         var
  150.             where: point;
  151.             inRGBColor, OutRGBColor: RGBColor;
  152.             index, mloc: integer;
  153.     begin
  154.         SetupLUTUndo;
  155.         with info^ do begin
  156.                 SetPort(LUTWindow);
  157.                 mloc := getvloc;
  158.                 if mloc < ColorStart then begin
  159.                         GetNewColor(FillColor1);
  160.                         UpdateLUT;
  161.                         exit(EditPseudoColors);
  162.                     end;
  163.                 if mloc > ColorEnd then begin
  164.                         GetNewColor(FillColor2);
  165.                         UpdateLUT;
  166.                         exit(EditPseudoColors);
  167.                     end;
  168.                 index := GetPseudoColorIndex;
  169.                 with inRGBColor do begin
  170.                         red := bsl(RedLUT[index], 8);
  171.                         green := bsl(GreenLUT[index], 8);
  172.                         blue := bsl(BlueLUT[index], 8);
  173.                     end;
  174.                 outRGBColor := inRGBColor;
  175.                 where.h := 0;
  176.                 where.v := 0;
  177.                 InitCursor;
  178.                 if GetColor(where, 'Pick a color, any color...', inRGBColor, outRGBColor) then begin
  179.                         with outRGBColor do begin
  180.                                 RedLUT[index] := bsr(red, 8);
  181.                                 GreenLUT[index] := bsr(green, 8);
  182.                                 BlueLUT[index] := bsr(blue, 8);
  183.                             end;
  184.                         changes := true;
  185.                     end;
  186.                 ColorTable := CustomTable;
  187.                 LutMode := PseudoColor;
  188.                 UpdateLUT;
  189.             end; {with}
  190.     end;
  191.  
  192.  
  193.     function EditSliceColor: boolean;
  194.         var
  195.             where: point;
  196.             inRGBColor, OutRGBColor: RGBColor;
  197.             vloc: integer;
  198.     begin
  199.         SetPort(LUTWindow);
  200.         vloc := getvloc;
  201.         if (vloc >= SliceStart) and (vloc <= SliceEnd) then begin
  202.                 GetNewColor(SliceColor);
  203.                 DrawDensitySlice(false);
  204.                 EditSliceColor := true
  205.             end
  206.         else
  207.             EditSliceColor := false;
  208.     end;
  209.  
  210.  
  211.     procedure ShowLUTValues (tStart, tEnd: integer);
  212.         var
  213.             tPort: GrafPtr;
  214.             value: extended;
  215.             range, NewMin, NewMax: LongInt;
  216.     begin
  217.         with info^ do begin
  218.                 GetPort(tPort);
  219.                 SetPort(InfoWindow);
  220.                 TextSize(9);
  221.                 TextFont(Monaco);
  222.                 TextMode(SrcCopy);
  223.                 MoveTo(xValueLoc, InfoVStart);
  224.                 if DataType <> EightBits then begin
  225.                         range := CurrentMax - CurrentMin;
  226.                         if tEnd < 255 then
  227.                             NewMin := CurrentMin + round(((255 - tEnd) / 255.0) * range)
  228.                         else
  229.                             NewMin := CurrentMin;
  230.                         DrawLong(NewMin);
  231.                         DrawString('    ');
  232.                         MoveTo(xValueLoc, InfoVStart + 10);
  233.                         if tStart > 0 then
  234.                             NewMax := CurrentMax - round((tStart / 255.0) * range)
  235.                         else
  236.                             NewMax := CurrentMax;
  237.                         DrawLong(NewMax);
  238.                         DrawString('    ');
  239.                         SetPort(tPort);
  240.                         exit(ShowLUTValues);
  241.                     end;
  242.                 if fit <> uncalibrated then begin
  243.                         if tStart >= 0 then
  244.                             value := cvalue[tStart]
  245.                         else
  246.                             value := cvalue[0];
  247.                         DrawReal(value, 5, 2);
  248.                         DrawString(' (');
  249.                         DrawReal(tStart, 3, 0);
  250.                         DrawString(')');
  251.                     end
  252.                 else
  253.                     DrawReal(tStart, 3, 0);
  254.                 DrawString('    ');
  255.                 MoveTo(xValueLoc, InfoVStart + 10);
  256.                 if fit <> uncalibrated then begin
  257.                         if tEnd <= 255 then
  258.                             value := cvalue[tEnd]
  259.                         else
  260.                             value := cvalue[255];
  261.                         DrawReal(value, 5, 2);
  262.                         DrawString(' (');
  263.                         DrawReal(tEnd, 3, 0);
  264.                         DrawString(')');
  265.                     end
  266.                 else
  267.                     DrawReal(tEnd, 3, 0);
  268.                 DrawString('    ');
  269.                 SetPort(tPort);
  270.             end;
  271.     end;
  272.  
  273.  
  274.     procedure ShowRGBValues (index: integer);
  275.         var
  276.             tPort: GrafPtr;
  277.             vloc: integer;
  278.     begin
  279.         with info^ do begin
  280.                 GetPort(tPort);
  281.                 SetPort(InfoWindow);
  282.                 TextSize(9);
  283.                 TextFont(Monaco);
  284.                 TextMode(SrcCopy);
  285.                 vloc := InfoVStart;
  286.                 MoveTo(xValueLoc, vloc);
  287.                 DrawLong(index);
  288.                 DrawString('    ');
  289.                 if Info^.fit <> uncalibrated then begin
  290.                         vloc := vloc + 10;
  291.                         MoveTo(xValueLoc, vloc);
  292.                         DrawReal(cvalue[index], 1, precision);
  293.                         DrawString('    ');
  294.                     end;
  295.                 vloc := vloc + 10;
  296.                 MoveTo(xValueLoc, vloc);
  297.                 DrawRGB(index);
  298.                 DrawString('    ');
  299.                 SetPort(tPort);
  300.             end;
  301.     end;
  302.  
  303.  
  304.     procedure FindPoints (var x1, y1, x2, y2: integer);
  305.     begin
  306.         with info^ do begin
  307.                 if ColorStart >= 0 then begin
  308.                         x1 := ColorStart;
  309.                         y1 := 0;
  310.                     end
  311.                 else begin
  312.                         x1 := 0;
  313.                         if ColorEnd > ColorStart then
  314.                             y1 := -ColorStart * 255 div (ColorEnd - ColorStart)
  315.                         else
  316.                             y1 := 0;
  317.                     end;
  318.                 if ColorEnd <= 255 then begin
  319.                         x2 := ColorEnd;
  320.                         y2 := 255;
  321.                     end
  322.                 else begin
  323.                         x2 := 255;
  324.                         if ColorEnd > ColorStart then
  325.                             y2 := 255 * (255 - ColorStart) div (ColorEnd - ColorStart)
  326.                         else
  327.                             y2 := 255;
  328.                     end;
  329.             end;
  330.     end;
  331.  
  332.  
  333.     procedure UpdateMap;
  334.         var
  335.             r: rect;
  336.             x, y, i, h1, h2, h3, v1, v2, v3, dx, dy: integer;
  337.             xcenter, ycenter, brightness, islope, thumb: integer;
  338.             width, max: integer;
  339.             table: LookupTable;
  340.             hrect: rect;
  341.             slope: extended;
  342.             area, value, sum: LongInt;
  343.             p1x, p1y, p2x, p2y: integer;
  344.     begin
  345.         with info^ do begin
  346.                 FindPoints(p1x, p1y, p2x, p2y);
  347.                 SetPort(MapWindow);
  348.                 PenNormal;
  349.                 EraseRect(MapRect2);
  350.                 FrameRect(MapRect1);
  351.                 if LutMode = CustomGrayscale then begin
  352.                         GetLookupTable(table);
  353.                         MoveTo(gmRectLeft, gmRectBottom - 1);
  354.                         for i := 0 to 63 do begin
  355.                                 x := gmRectLeft + i;
  356.                                 y := gmRectBottom - table[i * 4] div 4 - 1;
  357.                                 LineTo(x, y);
  358.                             end;
  359.                         EraseRect(gmSlide1i);
  360.                         EraseRect(gmSlide2i);
  361.                         exit(UpdateMap);
  362.                     end;
  363.                 h1 := gmRectLeft + p1x div 4;
  364.                 v1 := gmRectBottom - 1 - (p1y div 4);
  365.                 h2 := gmRectLeft + p2x div 4;
  366.                 v2 := gmRectBottom - 1 - (p2y div 4);
  367.                 MoveTo(gmRectLeft, gmRectBottom - 1);
  368.                 LineTo(h1, v1);
  369.                 LineTo(h2, v2);
  370.                 LineTo(gmRectRight - 1, gmRectTop);
  371.                 SetRect(hrect, h1 - 1, v1 - 1, h1 + 2, v1 + 2);
  372.                 PaintRect(hrect); {First handle}
  373.                 SetRect(hrect, h2 - 1, v2 - 1, h2 + 2, v2 + 2);
  374.                 PaintRect(hrect); {Last handle}
  375.                 dx := p2x - p1x;
  376.                 dy := p2y - p1y;
  377.                 xcenter := p1x + dx div 2;
  378.                 ycenter := p1y + dy div 2;
  379.                 h3 := gmRectLeft + xcenter div 4;
  380.                 v3 := gmRectBottom - 1 - (ycenter div 4);
  381.                 SetRect(hrect, h3 - 1, v3 - 1, h3 + 2, v3 + 2);
  382.                 PaintRect(hrect); {Center handle}
  383.                 thumb := gmSlideHeight - 2;
  384.                 max := gmSlideWidth - thumb - 2;
  385.                 width := ColorEnd - ColorStart;
  386.                 brightness := trunc(max * ((ColorStart + width) / (width + 255)));
  387.                 with gmSlide1 do
  388.                     SetRect(hrect, left + brightness + 1, top + 1, left + brightness + thumb + 1, top + thumb + 1);
  389.                 EraseRect(gmSlide1i);
  390.                 PaintRect(hrect);  {Thumb for contrast control}
  391.                 if dx <> 0 then
  392.                     slope := dy / dx
  393.                 else
  394.                     slope := 1000.0;
  395.                 if slope > 1.0 then begin
  396.                         if dy <> 0 then
  397.                             slope := 2.0 - dx / dy
  398.                         else
  399.                             slope := 2.0;
  400.                     end;
  401.                 islope := trunc(slope * 0.5 * (gmSlideWidth - thumb - 2.0));
  402.                 with gmSlide2 do
  403.                     SetRect(hrect, left + islope + 1, top + 1, left + islope + thumb + 1, top + thumb + 1);
  404.                 EraseRect(gmSlide2i);
  405.                 PaintRect(hrect);  {Thumb for contrast control}
  406.                 if ScreenDepth <> 8 then begin
  407.                         if ScreenDepth > 2 then
  408.                             DrawLut;
  409.                         UpdatePicWindow;
  410.                     end;
  411.             end;
  412.     end;
  413.  
  414.  
  415.     procedure UpdateThreshold;
  416.         var
  417.             level: integer;
  418.     begin
  419.         DrawLabels('Thresh:', '', '');
  420.         ShowMessage('');
  421.         with info^ do
  422.             repeat
  423.                 SetPort(LUTWindow);
  424.                 level := GetVLoc;
  425.                 if level <= 255 then begin
  426.                         ColorStart := level;
  427.                         ColorEnd := level;
  428.                         UpdateLUT;
  429.                         UpdateMap;
  430.                     end;
  431.                 Show1Value(level, NoValue);
  432.             until not Button;
  433.     end;
  434.  
  435.  
  436.     procedure UpdateDensitySlice;
  437.         var
  438.             mloc, saveloc, width, delta: integer;
  439.             adjust: (lower, upper, both);
  440.     begin
  441.         DrawLabels('Lower:', 'Upper:', '');
  442.         SetPort(LUTWindow);
  443.         mloc := getvloc;
  444.         saveloc := mloc;
  445.         width := SliceEnd - SliceStart + 1;
  446.         adjust := lower;
  447.         if mloc > (SliceStart + width div 4) then
  448.             adjust := both;
  449.         if mloc > (SliceEnd - width div 4) then
  450.             adjust := upper;
  451.         if (SliceStart = SliceEnd) and (abs(mloc - SliceStart) <= 2) and (SliceStart > 1) and (SliceEnd < 254) then
  452.             adjust := both;
  453.         while button do begin
  454.                 width := SliceEnd - SliceStart + 1;
  455.                 mloc := getvloc;
  456.                 delta := mloc - saveloc;
  457.                 saveloc := mloc;
  458.                 case adjust of
  459.                     lower:  begin
  460.                             SliceStart := mloc;
  461.                             if SliceStart < 1 then
  462.                                 SliceStart := 1;
  463.                             if SliceStart > SliceEnd then
  464.                                 SliceStart := SliceEnd;
  465.                         end;
  466.                     upper:  begin
  467.                             SliceEnd := mloc;
  468.                             if SliceEnd > 254 then
  469.                                 SliceEnd := 254;
  470.                             if SliceEnd < SliceStart then
  471.                                 SliceEnd := SliceStart;
  472.                         end;
  473.                     both:  begin
  474.                             if mloc <= 1 then begin
  475.                                     SliceStart := 1;
  476.                                     SliceEnd := width;
  477.                                 end
  478.                             else if mloc >= 254 then begin
  479.                                     SliceEnd := 254;
  480.                                     SliceStart := 254 - width + 1;
  481.                                 end
  482.                             else if ((SliceStart + delta) >= 1) and ((SliceEnd + delta) <= 254) then begin
  483.                                     SliceStart := SliceStart + delta;
  484.                                     SliceEnd := SliceEnd + delta;
  485.                                 end;
  486.                         end;
  487.                 end; {case}
  488.                 DrawDensitySlice(OptionKeyDown);
  489.                 ShowLUTValues(SliceStart, SliceEnd);
  490.             end; {while}
  491.         DrawDensitySlice(false)
  492.     end;
  493.  
  494.  
  495.     procedure EditExtraColors (entry: integer);
  496.         var
  497.             where: point;
  498.             inRGBColor, OutRGBColor: RGBColor;
  499.     begin
  500.         if (entry <> WhiteIndex) and (entry <> BlackIndex) then begin
  501.                 inRGBColor := ExtraColors[entry];
  502.                 outRGBColor := inRGBColor;
  503.                 where.h := 0;
  504.                 where.v := 0;
  505.                 InitCursor;
  506.                 if GetColor(where, 'Pick a color, any color...', inRGBColor, outRGBColor) then
  507.                     with info^ do begin
  508.                             ExtraColors[entry] := OutRGBColor;
  509.                             changes := true;
  510.                             LoadLUT(cTable);
  511.                         end
  512.             end
  513.         else
  514.             PutError('Sorry, but you can not edit white or black.');
  515.     end;
  516.  
  517.  
  518.     function GetColorFromLUT (DoubleClick: boolean): integer;
  519.         var
  520.             mloc, color, i: integer;
  521.             loc: point;
  522.     begin
  523.         SetPort(LUTWindow);
  524.         GetMouse(loc);
  525.         if loc.v > 255 then begin
  526.                 color := 0;
  527.                 for i := 1 to nExtraColors + 2 do
  528.                     if PtInRect(loc, ExtraColorsRect[i]) then
  529.                         Color := ExtraColorsEntry[i];
  530.                 if DoubleClick then
  531.                     EditExtraColors(color);
  532.                 GetColorFromLUT := color;
  533.             end
  534.         else
  535.             GetColorFromLUT := loc.v;
  536.     end;
  537.  
  538.  
  539.     function isGrayScaleLUT: boolean;
  540.         var
  541.             i: integer;
  542.             GrayScaleLUT: boolean;
  543.     begin
  544.         with info^ do begin
  545.                 GrayscaleLUT := true;
  546.                 i := 0;
  547.                 repeat
  548.                     with cTable[i].rgb do
  549.                         GrayscaleLUT := GrayscaleLUT and (red = green) and (green = blue);
  550.                     i := i + 1;
  551.                 until (i = 256) or not GrayscaleLUT;
  552.                 isGrayScaleLUT := GrayScaleLUT;
  553.             end;
  554.     end;
  555.  
  556.  
  557.     procedure SetupPseudocolor;
  558.         var
  559.             i: integer;
  560.     begin
  561.         with info^ do begin
  562.                 DisableDensitySlice;
  563.                 Thresholding := false;
  564.                 for i := 1 to 254 do
  565.                     with cTable[i].rgb do begin
  566.                             RedLUT[i] := band(bsr(red, 8), 255);
  567.                             GreenLUT[i] := band(bsr(green, 8), 255);
  568.                             BlueLUT[i] := band(bsr(blue, 8), 255);
  569.                         end;
  570.                 RedLUT[0] := RedLUT[1];
  571.                 GreenLUT[0] := GreenLUT[1];
  572.                 BlueLUT[0] := BlueLUT[1];
  573.                 RedLUT[255] := RedLUT[254];
  574.                 GreenLUT[255] := GreenLUT[254];
  575.                 BlueLUT[255] := BlueLUT[254];
  576.                 nColors := 256;
  577.                 ColorStart := 0;
  578.                 ColorEnd := 255;
  579.                 FillColor1 := ctable[1].rgb;
  580.                 FillColor2 := ctable[254].rgb;
  581.                 InvertedColorTable := false;
  582.             end;
  583.     end;
  584.  
  585.  
  586.     procedure ShowLabels;
  587.     begin
  588.         with info^ do
  589.             if DataType <> EightBits then
  590.                 DrawLabels('Min:', 'Max:', '')
  591.             else
  592.                 DrawLabels('Lower:', 'Upper:', '');
  593.     end;
  594.  
  595.  
  596.     procedure AdjustLUT;
  597.         const
  598.             MinWidth = 8;
  599.         var
  600.             mloc, saveloc, width, delta, cstart, cend: integer;
  601.             adjust: (lower, upper, both);
  602.             loc: point;
  603.     begin
  604.         with info^ do begin
  605.                 SetPort(LUTWindow);
  606.                 SetupLutUndo;
  607.                 ShowLabels;
  608.                 mloc := getvloc;
  609.                 saveloc := mloc;
  610.                 cstart := ColorStart;
  611.                 if cstart < 0 then
  612.                     cstart := 0;
  613.                 cend := ColorEnd;
  614.                 if cend > 255 then
  615.                     cend := 255;
  616.                 width := cend - cstart + 1;
  617.                 adjust := lower;
  618.                 if mloc > (cstart + width div 4) then
  619.                     adjust := both;
  620.                 if mloc > (cend - width div 4) then
  621.                     adjust := upper;
  622.                 while button do begin
  623.                         SetPort(LUTWindow);
  624.                         GetMouse(loc);
  625.                         mloc := loc.v;
  626.                         delta := mloc - saveloc;
  627.                         saveloc := mloc;
  628.                         case adjust of
  629.                             lower:  begin
  630.                                     ColorStart := mloc;
  631.                                     cend := ColorEnd;
  632.                                     if cend > 255 then
  633.                                         cend := 255;
  634.                                     if ColorStart > (cend - MinWidth) then
  635.                                         ColorStart := cend - MinWidth;
  636.                                 end;
  637.                             upper:  begin
  638.                                     ColorEnd := mloc;
  639.                                     cstart := ColorStart;
  640.                                     if cstart < 0 then
  641.                                         cstart := 0;
  642.                                     if ColorEnd < (cstart + MinWidth) then
  643.                                         ColorEnd := cstart + MinWidth;
  644.                                 end;
  645.                             both: 
  646.                                 if (mloc >= 0) and (mloc <= 255) then begin
  647.                                         ColorStart := ColorStart + delta;
  648.                                         ColorEnd := ColorEnd + delta;
  649.                                     end;
  650.                         end;
  651.                         UpdateLUT;
  652.                         UpdateMap;
  653.                         ShowLUTValues(ColorStart, ColorEnd);
  654.                     end;
  655.             end; {with info}
  656.     end;
  657.  
  658.  
  659.     procedure RotateLUT;
  660.         var
  661.             vstart, i, j, delta: integer;
  662.             loc: point;
  663.             TempTable: MyCSpecArray;
  664.     begin
  665.         with info^ do begin
  666.                 SetPort(LUTWindow);
  667.                 GetMouse(loc);
  668.                 vstart := loc.v;
  669.                 repeat
  670.                     GetMouse(loc);
  671.                     delta := vstart - loc.v;
  672.                     for i := 1 to 254 do begin {0 is resevred for white and 255 for black}
  673.                             j := i + delta;
  674.                             if j > 254 then
  675.                                 j := j - 254;
  676.                             if j > 254 then
  677.                                 j := 254;
  678.                             if j < 1 then
  679.                                 j := j + 254;
  680.                             if j < 1 then
  681.                                 j := 1;
  682.                             TempTable[i] := cTable[j]
  683.                         end;
  684.                     cTable := TempTable;
  685.                     LoadLUT(cTable);
  686.                     vstart := loc.v;
  687.                 until not button;
  688.                 SetupPseudocolor;
  689.                 ColorTable := CustomTable;
  690.             end;
  691.     end;
  692.  
  693.  
  694.     procedure DoMouseDownInLUT (event: EventRecord);
  695.         var
  696.             color: integer;
  697.             DoubleClick: boolean;
  698.     begin
  699.         with info^ do begin
  700.                 if CurrentTool = PickerTool then
  701.                     DoubleClick := (TickCount - LutTime) < GetDblTime
  702.                 else
  703.                     DoubleClick := false;
  704.                 LutTime := TickCount;
  705.                 if (CurrentTool <> LutTool) and (CurrentTool <> Wand) then begin
  706.                         color := GetColorFromLUT(DoubleClick);
  707.                         if (CurrentTool = eraser) or OptionKeyDown then
  708.                             SetBackgroundColor(color)
  709.                         else
  710.                             SetForegroundColor(color);
  711.                         if not DoubleClick then
  712.                             exit(DoMouseDownInLUT);
  713.                     end;
  714.                 if Thresholding then begin
  715.                         UpdateThreshold;
  716.                         exit(DoMouseDownInLUT)
  717.                     end;
  718.                 if DoubleClick then begin
  719.                         if DensitySlicing and (CurrentTool = PickerTool) then begin
  720.                                 if EditSliceColor then
  721.                                     exit(DoMouseDownInLUT);
  722.                             end;
  723.                         if CurrentTool = PickerTool then begin
  724.                                 EditPseudoColors;
  725.                                 exit(DoMouseDownInLUT)
  726.                             end;
  727.                     end; {if DoubleClick}
  728.                 if ((CurrentTool = LutTool) or (CurrentTool = Wand)) and DensitySlicing then begin
  729.                         UpdateDensitySlice;
  730.                         exit(DoMouseDownInLUT);
  731.                     end;
  732.                 if OptionKeyDown then
  733.                     RotateLUT
  734.                 else
  735.                     AdjustLUT;
  736.             end; {with}
  737.     end;
  738.  
  739.  
  740.     procedure DoCopyColor;
  741.     begin
  742.         with info^ do begin
  743.                 if ForegroundIndex = WhiteIndex then begin
  744.                         ClipboardColor := WhiteRGB;
  745.                         exit(DoCopyColor);
  746.                     end;
  747.                 if ForegroundIndex = BlackIndex then begin
  748.                         ClipboardColor := BlackRGB;
  749.                         exit(DoCopyColor);
  750.                     end;
  751.                 with cTable[ForegroundIndex].rgb do begin
  752.                         ClipboardColor.red := red;
  753.                         ClipboardColor.green := green;
  754.                         ClipboardColor.blue := blue;
  755.                     end;
  756.                 WhatsOnClip := AColor;
  757.                 ClipTextInBuffer := false;
  758.             end;
  759.     end;
  760.  
  761.  
  762.     procedure PasteColor;
  763.         var
  764.             CurrentColorIndex: integer;
  765.     begin
  766.         with info^ do begin
  767.                 if CurrentTool = PickerTool then begin
  768.                         if ForegroundIndex < ColorStart then begin
  769.                                 FillColor1 := ClipboardColor;
  770.                                 UpdateLUT;
  771.                                 exit(PasteColor);
  772.                             end;
  773.                         if ForegroundIndex > ColorEnd then begin
  774.                                 FillColor2 := ClipboardColor;
  775.                                 UpdateLUT;
  776.                                 exit(PasteColor);
  777.                             end;
  778.                         CurrentColorIndex := GetPseudoColorIndex;
  779.                         with ClipboardColor do begin
  780.                                 RedLUT[CurrentColorIndex] := bsr(red, 8);
  781.                                 GreenLUT[CurrentColorIndex] := bsr(green, 8);
  782.                                 BlueLUT[CurrentColorIndex] := bsr(blue, 8);
  783.                             end;
  784.                         ColorTable := CustomTable;
  785.                         UpdateLUT;
  786.                     end
  787.                 else
  788.                     beep;
  789.             end;
  790.     end;
  791.  
  792.  
  793.     procedure InvertPalette;
  794.         var
  795.             TempRed, TempGreen, TempBlue: LutArray;
  796.             i, LastColor: integer;
  797.             TempTable: MyCSpecArray;
  798.             TempFill: rgbColor;
  799.     begin
  800.         DisableDensitySlice;
  801.         DisableThresholding;
  802.         with info^ do begin
  803.                 TempRed := RedLUT;
  804.                 TempGreen := GreenLUT;
  805.                 TempBlue := BlueLUT;
  806.                 LastColor := ncolors - 1;
  807.                 for i := 0 to LastColor do begin
  808.                         RedLUT[i] := TempRed[LastColor - i];
  809.                         GreenLUT[i] := TempGreen[LastColor - i];
  810.                         BlueLUT[i] := TempBlue[LastColor - i];
  811.                     end;
  812.                 TempFill := FillColor1;
  813.                 FillColor1 := FillColor2;
  814.                 FillColor2 := TempFill;
  815.                 InvertedColorTable := not InvertedColorTable;
  816.                 IdentityFunction := false;
  817.             end;
  818.     end;
  819.  
  820.  
  821.     procedure DrawMap;
  822.         var
  823.             x, y, i: integer;
  824.             table: LookupTable;
  825.     begin
  826.         SetPort(MapWindow);
  827.         PenNormal;
  828.         TextFont(Geneva);
  829.         TextSize(9);
  830.         with gmSlide1 do
  831.             MoveTo(left - 6, bottom);
  832.         DrawChar('B');
  833.         with gmSlide2 do
  834.             MoveTo(left - 6, bottom);
  835.         DrawChar('C');
  836.         FrameRect(gmSlide1);
  837.         FrameRect(gmSlide2);
  838.         FrameRect(gmIcon1);
  839.         FrameRect(gmIcon2);
  840.         with gmIcon1 do begin
  841.                 MoveTo(left, top + 10);
  842.                 LineTo(left + 5, top + 10);
  843.                 LineTo(left + 12, top + 3);
  844.                 LineTo(left + gmIconWidth - 1, top + 3);
  845.             end;
  846.         with gmIcon2 do begin
  847.                 MoveTo(left, top + 10);
  848.                 LineTo(left + gmIconWidth div 2, top + 10);
  849.                 LineTo(left + gmIconWidth div 2, top + 3);
  850.                 LineTo(left + gmIconWidth - 1, top + 3);
  851.             end;
  852.         UpdateMap;
  853.         GrayMapReady := true;
  854.     end;
  855.  
  856.  
  857.     procedure ResetGrayMap;
  858.         var
  859.             i: integer;
  860.     begin
  861.         with info^ do begin
  862.                 DisableDensitySlice;
  863.                 for i := 0 to 255 do begin
  864.                         RedLut[i] := 255 - i;
  865.                         GreenLut[i] := 255 - i;
  866.                         BlueLut[i] := 255 - i;
  867.                     end;
  868.                 FillColor1 := WhiteRGB;
  869.                 FillColor2 := BlackRGB;
  870.                 ColorStart := 0;
  871.                 ColorEnd := 255;
  872.                 nColors := 256;
  873.                 ColorTable := CustomTable;
  874.                 LUTMode := Grayscale;
  875.                 UpdateLUT;
  876.                 if GrayMapReady then
  877.                     UpdateMap;
  878.                 IdentityFunction := true;
  879.                 InvertedColorTable := false;
  880.             end;
  881.     end;
  882.  
  883.  
  884.     procedure AdjustBrightness;
  885.         var
  886.             loc, max, thumb, xcenter, ycenter, width: integer;
  887.             p: point;
  888.     begin
  889.         with info^ do begin
  890.                 thumb := gmSlideHeight - 2;
  891.                 max := gmSlideWidth - thumb - 2;
  892.                 width := ColorEnd - ColorStart;
  893.                 ShowLabels;
  894.                 repeat
  895.                     GetMouse(p);
  896.                     loc := p.h - gmSlide1.left - 2;
  897.                     if loc < 0 then
  898.                         loc := 0;
  899.                     if loc > max then
  900.                         loc := max;
  901.                     ColorStart := -width + round((width + 255) * (loc / max));
  902.                     ColorEnd := ColorStart + width;
  903.                     UpdateLUT;
  904.                     UpdateMap;
  905.                     ShowLUTValues(ColorStart, ColorEnd);
  906.                 until not button;
  907.                 IdentityFunction := false;
  908.             end; {with}
  909.     end;
  910.  
  911.  
  912.     procedure AdjustContrast;
  913.         var
  914.             p: point;
  915.             loc, max, HalfMax, thumb: integer;
  916.             slope, center: extended;
  917.     begin
  918.         with info^ do begin
  919.                 thumb := gmSlideHeight - 2;
  920.                 max := gmSlideWidth - thumb - 2;
  921.                 HalfMax := max div 2;
  922.                 center := ColorStart + (ColorEnd - ColorStart) / 2.0;
  923.                 ShowLabels;
  924.                 repeat
  925.                     GetMouse(p);
  926.                     loc := p.h - gmSlide2.left - 2;
  927.                     if loc < 0 then
  928.                         loc := 0;
  929.                     if loc > max then
  930.                         loc := max;
  931.                     if loc <= HalfMax then
  932.                         slope := loc / HalfMax
  933.                     else if loc < max then
  934.                         slope := HalfMax / (max - loc)
  935.                     else
  936.                         slope := 1000.0;
  937.                     if slope > 0.0 then begin
  938.                             ColorStart := round(center - 127.5 / slope);
  939.                             ColorEnd := round(center + 127.5 / slope);
  940.                         end
  941.                     else begin
  942.                             ColorStart := round(center - MaxColor);
  943.                             ColorEnd := round(center + MaxColor);
  944.                         end;
  945.                     if ColorEnd < 0 then
  946.                         ColorEnd := 0;
  947.                     if ColorStart > 255 then
  948.                         ColorStart := 255;
  949.                     UpdateLUT;
  950.                     UpdateMap;
  951.                     ShowLUTValues(ColorStart, ColorEnd);
  952.                 until not button;
  953.                 IdentityFunction := false;
  954.             end; {with}
  955.     end;
  956.  
  957.  
  958.     procedure ConvertMouseToXY (p: point; var x, y: integer);
  959.     begin
  960.         x := (p.h - gmRectLeft) * 4;
  961.         if x < 0 then
  962.             x := 0;
  963.         if x > 255 then
  964.             x := 255;
  965.         y := (gmRectBottom - p.v) * 4;
  966.         if y < 0 then
  967.             y := 0;
  968.         if y > 255 then
  969.             y := 255;
  970.     end;
  971.  
  972.  
  973.     procedure DoFreehandEditing;
  974.         var
  975.             p: point;
  976.             x1, x2, y, i: integer;
  977.             FirstTime: boolean;
  978.     begin
  979.         with info^ do begin
  980.                 LUTMode := CustomGrayscale;
  981.                 SetPort(MapWindow);
  982.                 FirstTime := true;
  983.                 while button do begin
  984.                         x1 := x2;
  985.                         GetMouse(p);
  986.                         ConvertMouseToXY(p, x2, y);
  987.                         if x2 > 252 then
  988.                             x2 := 252;
  989.                         if FirstTime then begin
  990.                                 x1 := x2;
  991.                                 FirstTime := false;
  992.                             end;
  993.                         if x2 >= x1 then
  994.                             for i := x1 to x2 + 3 do
  995.                                 with cTable[i].rgb do begin
  996.                                         red := bsl(255 - y, 8);
  997.                                         green := bsl(255 - y, 8);
  998.                                         blue := bsl(255 - y, 8);
  999.                                     end
  1000.                         else
  1001.                             for i := x1 + 3 downto x2 do
  1002.                                 with cTable[i].rgb do begin
  1003.                                         red := bsl(255 - y, 8);
  1004.                                         green := bsl(255 - y, 8);
  1005.                                         blue := bsl(255 - y, 8);
  1006.                                     end;
  1007.                         DrawMap;
  1008.                         LoadLUT(cTable);
  1009.                         if ScreenDepth <> 8 then UpdatePicWindow;
  1010.                     end;
  1011.                 if not isGrayscaleLut then
  1012.                     LutMode := ColorLut;
  1013.             end;
  1014.     end;
  1015.  
  1016.  
  1017.     procedure DisableThresholding;
  1018.     begin
  1019.         with info^ do
  1020.             if thresholding then begin
  1021.                 ColorStart := SaveColorStart;
  1022.                 ColorEnd := SaveColorEnd;
  1023.                 FillColor1 := SaveFill1;
  1024.                 FillColor2 := SaveFill2;
  1025.                 UpdateLut;
  1026.                 UpdateMap;
  1027.                 Thresholding := false;
  1028.             end;
  1029.     end;
  1030.  
  1031.  
  1032.     procedure EnableThresholding (level: integer);
  1033.     begin
  1034.         with info^ do begin
  1035.             if not thresholding then begin
  1036.                 SaveColorStart := ColorStart;
  1037.                 SaveColorEnd := ColorEnd;
  1038.                 SaveFill1 := FillColor1;
  1039.                 SaveFill2 := FillColor2;
  1040.             end;
  1041.             ColorStart := level;
  1042.             ColorEnd := level;
  1043.             FillColor1 := WhiteRGB;
  1044.             FillColor2 := BlackRGB;
  1045.             UpdateLut;
  1046.             UpdateMap;
  1047.             Thresholding := true;
  1048.             if not macro then
  1049.                 SelectLutTool;
  1050.         end;
  1051.     end;
  1052.  
  1053.  
  1054.     procedure ResetMap;
  1055.     begin
  1056.         with info^ do begin
  1057.                 ColorStart := 0;
  1058.                 ColorEnd := 255;
  1059.                 if Thresholding then begin
  1060.                         FillColor1 := SaveFill1;
  1061.                         FillColor2 := SaveFill2;
  1062.                     end;
  1063.                 IdentityFunction := LutMode = Grayscale;
  1064.                 UpdateLUT;
  1065.                 UpdateMap;
  1066.             end;
  1067.     end;
  1068.  
  1069.  
  1070.     procedure DoMouseDownInMap;
  1071.         var
  1072.             r: rect;
  1073.             x, y, p1Dist, p2Dist: integer;
  1074.             mode: (StartPoint, EndPoint, Brightness, AdjustThreshold);
  1075.             p: point;
  1076.             pressed: boolean;
  1077.             x1, y1, x2, y2: integer;
  1078.             xintercept: integer;
  1079.             deltax, deltay, width: LongInt;
  1080.  
  1081.         procedure DoFixup;
  1082.         begin
  1083.             with info^ do
  1084.                 if ((x1 = 0) and (x2 = 0)) or ((x1 = 255) and (x2 = 255)) then begin
  1085.                         y1 := 0;
  1086.                         y2 := 255;
  1087.                     end;
  1088.         end;
  1089.  
  1090.     begin
  1091.         with info^ do begin
  1092.                 DisableDensitySlice;
  1093.                 if OptionKeyDown then begin
  1094.                         DoFreehandEditing;
  1095.                         exit(DoMouseDownInMap);
  1096.                     end;
  1097.                 if LUTMode = CustomGrayscale then
  1098.                     ResetGrayMap;
  1099.                 FindPoints(x1, y1, x2, y2);
  1100.                 SetPort(MapWindow);
  1101.                 GetMouse(p);
  1102.                 if PtInRect(p, gmIcon1) then begin
  1103.                         InvertRect(gmIcon1);
  1104.                         pressed := true;
  1105.                         while Button and pressed do begin
  1106.                                 GetMouse(p);
  1107.                                 if not PtInRect(p, gmIcon1) then begin
  1108.                                         InvertRect(gmIcon1);
  1109.                                         pressed := false;
  1110.                                     end;
  1111.                             end;
  1112.                         repeat
  1113.                         until not button;
  1114.                         if pressed then begin
  1115.                                 InvertRect(gmIcon1);
  1116.                                 ResetMap;
  1117.                                 exit(DoMouseDownInMap)
  1118.                             end;
  1119.                     end;
  1120.                 if PtInRect(p, gmIcon2) then begin
  1121.                         InvertRect(gmIcon2);
  1122.                         pressed := true;
  1123.                         while Button and pressed do begin
  1124.                                 GetMouse(p);
  1125.                                 if not PtInRect(p, gmIcon2) then begin
  1126.                                         InvertRect(gmIcon2);
  1127.                                         pressed := false;
  1128.                                     end;
  1129.                             end;
  1130.                         repeat
  1131.                         until not button;
  1132.                         if pressed then begin
  1133.                                 InvertRect(gmIcon2);
  1134.                                 if Thresholding then
  1135.                                     DisableThresholding
  1136.                                 else
  1137.                                     EnableThresholding(128);
  1138.                                 exit(DoMouseDownInMap)
  1139.                             end;
  1140.                     end;
  1141.                 if PtInRect(p, gmSlide1) then
  1142.                     AdjustBrightness;
  1143.                 if PtInRect(p, gmSlide2) then
  1144.                     AdjustContrast;
  1145.                 if p.v > (gmRectBottom + 4) then begin
  1146.                         if not thresholding and ((x2 - x1) <= 1) then begin
  1147.                                 thresholding := true;
  1148.                                 SaveFill1 := FillColor1;
  1149.                                 SaveFill2 := FillColor2;
  1150.                             end;
  1151.                         exit(DoMouseDownInMap);
  1152.                     end;
  1153.                 if LutMode = CustomGrayscale then
  1154.                     LutMode := Grayscale;
  1155.                 GetMouse(p);
  1156.                 ConvertMouseToXY(p, x, y);
  1157.                 if (x <= 24) or (y <= 32) then
  1158.                     mode := StartPoint
  1159.                 else if (x >= 224) or (y >= 232) then
  1160.                     mode := EndPoint
  1161.                 else if thresholding then
  1162.                     mode := AdjustThreshold
  1163.                 else
  1164.                     mode := brightness;
  1165.                 if mode = AdjustThreshold then
  1166.                     DrawLabels('Thresh:', '', '')
  1167.                 else
  1168.                     ShowLabels;
  1169.                 repeat
  1170.                     case mode of
  1171.                         StartPoint:  begin
  1172.                                 if thresholding then begin
  1173.                                         FillColor1 := SaveFill1;
  1174.                                         FillColor2 := SaveFill2;
  1175.                                     end;
  1176.                                 if x > y then
  1177.                                     y := 0
  1178.                                 else
  1179.                                     x := 0;
  1180.                                 x1 := x;
  1181.                                 if x1 > x2 then
  1182.                                     x2 := x1;
  1183.                                 y1 := y;
  1184.                                 if y1 > y2 then
  1185.                                     y2 := y1;
  1186.                                 DoFixUp;
  1187.                             end;
  1188.                         EndPoint:  begin
  1189.                                 if thresholding then begin
  1190.                                         FillColor1 := SaveFill1;
  1191.                                         FillColor2 := SaveFill2;
  1192.                                     end;
  1193.                                 if x > y then
  1194.                                     x := 255
  1195.                                 else
  1196.                                     y := 255;
  1197.                                 x2 := x;
  1198.                                 if x2 < x1 then
  1199.                                     x1 := x2;
  1200.                                 y2 := y;
  1201.                                 if y2 < y1 then
  1202.                                     y1 := y2;
  1203.                                 DoFixUp;
  1204.                             end;
  1205.                         Brightness:  begin
  1206.                                 deltax := x2 - x1;
  1207.                                 deltay := y2 - y1;
  1208.                                 if deltax = 0 then begin
  1209.                                         x1 := x;
  1210.                                         y1 := 0;
  1211.                                         x2 := x;
  1212.                                         y2 := 255;
  1213.                                     end
  1214.                                 else if deltay = 0 then begin
  1215.                                         x1 := 0;
  1216.                                         y1 := y;
  1217.                                         x2 := 255;
  1218.                                         y2 := y;
  1219.                                     end
  1220.                                 else begin
  1221.                                         x1 := x - y * deltax div deltay;
  1222.                                         xIntercept := x1;
  1223.                                         y1 := 0;
  1224.                                         if x1 < 0 then begin
  1225.                                                 y1 := -deltay * x1 div deltaX;
  1226.                                                 x1 := 0;
  1227.                                             end;
  1228.                                         y2 := 255;
  1229.                                         x2 := 255 * deltax div deltay;
  1230.                                         if xIntercept < 0 then
  1231.                                             x2 := x2 + xIntercept
  1232.                                         else
  1233.                                             x2 := x2 + x1;
  1234.                                         if x2 > 255 then begin
  1235.                                                 y2 := 255 - (x2 - 255) * deltay div deltax;
  1236.                                                 x2 := 255;
  1237.                                             end;
  1238.                                     end;
  1239.                                 if x2 < 1 then
  1240.                                     x2 := 1;
  1241.                                 if y2 < 1 then
  1242.                                     y2 := 1;
  1243.                                 if x1 > 254 then
  1244.                                     x1 := 254;
  1245.                                 if y1 > 254 then
  1246.                                     y1 := 254;
  1247.                             end;
  1248.                         AdjustThreshold:  begin
  1249.                                 x1 := x;
  1250.                                 y1 := 0;
  1251.                                 x2 := x;
  1252.                                 y2 := 255;
  1253.                             end;
  1254.                     end; {case}
  1255. {showmessage(concat(long2str(x1), '  ', long2str(y1), '  ', long2str(x2), '  ', long2str(y2), crStr, long2str(ColorStart), '  ', long2str(ColorEnd)));}
  1256.                     width := x2 - x1;
  1257.                     if y1 = 0 then
  1258.                         ColorStart := x1
  1259.                     else begin
  1260.                             if (y2 > y1) then
  1261.                                 ColorStart := -width * y1 div (y2 - y1)
  1262.                             else
  1263.                                 ColorStart := -MaxColor;
  1264.                         end;
  1265.                     if y2 = 255 then
  1266.                         ColorEnd := x2
  1267.                     else begin
  1268.                             if (y2 > y1) then
  1269.                                 ColorEnd := 255 + width * (255 - y2) div ((y2 - y1))
  1270.                             else
  1271.                                 ColorEnd := MaxColor;
  1272.                         end;
  1273.                     UpdateLUT;
  1274.                     UpdateMap;
  1275.                     if thresholding then
  1276.                         Show1Value(ColorStart, NoValue)
  1277.                     else
  1278.                         ShowLUTValues(ColorStart, ColorEnd);
  1279.                     GetMouse(p);
  1280.                     ConvertMouseToXY(p, x, y);
  1281.                 until not Button;
  1282.                 IdentityFunction := false;
  1283.                 if not thresholding and ((x2 - x1) <= 1) then begin
  1284.                         thresholding := true;
  1285.                         SaveFill1 := FillColor1;
  1286.                         SaveFill2 := FillColor2;
  1287.                     end;
  1288.             end; {with info}
  1289.     end;
  1290.  
  1291.  
  1292.     procedure DrawLUT;
  1293.         var
  1294.             tPort: GrafPtr;
  1295.             h, v, i: integer;
  1296.     begin
  1297.         GetPort(tPort);
  1298.         SetPort(LUTWindow);
  1299.         with LutWindow^ do begin
  1300.                 for v := 0 to 255 do begin
  1301.                         SetFColor(v);
  1302.                         MoveTo(0, v);
  1303.                         LineTo(cwidth, v)
  1304.                     end;
  1305.                 for i := 1 to nExtraColors + 2 do begin
  1306.                         SetFColor(ExtraColorsEntry[i]);
  1307.                         PaintRect(ExtraColorsRect[i]);
  1308.                     end;
  1309.                 TextFont(Geneva);
  1310.                 TextSize(9);
  1311.                 with ExtraColorsRect[1] do
  1312.                     MoveTo(left + 3, bottom - 1);
  1313.                 SetFColor(BlackIndex);
  1314.                 DrawString('white');
  1315.                 with ExtraColorsRect[2] do
  1316.                     MoveTo(left + 4, bottom - 1);
  1317.                 InvertRect(ExtraColorsRect[2]);
  1318.                 DrawString('black');
  1319.                 InvertRect(ExtraColorsRect[2]);
  1320.             end;
  1321.         SetPort(tPort);
  1322.     end;
  1323.  
  1324.  
  1325.     function LoadPP2Palette: boolean;
  1326. {Loads COLR resource from PixelPaint 2.0 palette file.}
  1327.         var
  1328.             i: integer;
  1329.             size: LongInt;
  1330.             h: Handle;
  1331.             PPColorTable: record
  1332.                     ctSize: INTEGER;
  1333.                     table: array[0..255] of RGBColor;
  1334.                 end;
  1335.     begin
  1336.         h := GetResource('COLR', 999);
  1337.         size := GetHandleSize(handle(h));
  1338.         if (ResError = NoErr) and (size = 1538) then
  1339.             with info^ do begin
  1340.                     BlockMove(handle(h)^, @PPColorTable, SizeOf(PPColorTable));
  1341.                     with PPColorTable do begin
  1342.                             for i := 0 to 255 do
  1343.                                 cTable[i].rgb := table[i];
  1344.                         end;
  1345.                     LoadLUT(cTable);
  1346.                     LutMode := ColorLut;
  1347.                     SetupPseudocolor;
  1348.                     IdentityFunction := false;
  1349.                     LoadPP2Palette := true;
  1350.                 end
  1351.         else
  1352.             LoadPP2Palette := false;
  1353.         if h <> nil then
  1354.             DisposeHandle(h);
  1355.     end;
  1356.  
  1357.  
  1358.     procedure LoadColorTable (theColorTable: CTabHandle);
  1359.         const
  1360.             ExpectedSize = 2056;
  1361.         var
  1362.             size: LongInt;
  1363.             MyColorTable: record
  1364.                     ctSeed: LONGINT;
  1365.                     transIndex: INTEGER;
  1366.                     ctSize: INTEGER;
  1367.                     ctTable: MyCSpecArray;
  1368.                 end;
  1369.     begin
  1370.         size := GetHandleSize(handle(theColorTable));
  1371.         if size < ExpectedSize then
  1372.             exit(LoadColorTable);
  1373.         if size > ExpectedSize then
  1374.             Size := ExpectedSize;
  1375.         BlockMove(handle(theColorTable)^, @MyColorTable, size);
  1376.         LoadLUT(MyColorTable.ctTable);
  1377.         with info^ do begin
  1378.                 cTable := MyColorTable.ctTable;
  1379.                 LutMode := ColorLut;
  1380.                 IdentityFunction := false;
  1381.             end;
  1382.         SetupPseudocolor;
  1383.     end;
  1384.  
  1385.  
  1386.     function LoadCLUTResource;{(id:integer):boolean}
  1387.         const
  1388.             ExpectedSize = 2056;
  1389.         var
  1390.             Size: LongInt;
  1391.             h: cTabHandle;
  1392.     begin
  1393.         DisableDensitySlice;
  1394.         h := GetCTable(id);
  1395.         size := GetHandleSize(handle(h));
  1396.         if (ResError <> NoErr) or (size < ExpectedSize) then begin
  1397.                 LoadCLUTResource := false;
  1398.                 if id = PixelpaintID then begin
  1399.                         if LoadPP2Palette then
  1400.                             LoadCLUTResource := true;
  1401.                     end;
  1402.                 if h <> nil then
  1403.                     DisposeCTable(h);
  1404.                 exit(LoadCLUTResource)
  1405.             end;
  1406.         LoadColorTable(h);
  1407.         DisposeCTable(h);
  1408.         LoadCLUTResource := true;
  1409.     end;
  1410.  
  1411.  
  1412.     procedure GetLookupTable;{(VAR table:LookupTable)}
  1413.         var
  1414.             i, r, g, b: integer;
  1415.             GrayscaleImage: boolean;
  1416.     begin
  1417.         with info^ do begin
  1418.                 if DensitySlicing then begin
  1419.                         for i := 0 to 255 do
  1420.                             if (i >= SliceStart) and (i <= SliceEnd) then begin
  1421.                                     if ThresholdToForeground then
  1422.                                         table[i] := ForegroundIndex
  1423.                                     else
  1424.                                         table[i] := i
  1425.                                 end
  1426.                             else begin
  1427.                                     if NonThresholdToBackground then
  1428.                                         table[i] := BackgroundIndex
  1429.                                     else
  1430.                                         table[i] := i
  1431.                                 end;
  1432.                         DisableDensitySlice;
  1433.                         exit(GetLookupTable);
  1434.                     end;
  1435.                 if (LutMode = GrayScale) or (LutMode = CustomGrayscale) then
  1436.                     for i := 0 to 255 do
  1437.                         table[i] := 255 - BSR(cTable[i].RGB.red, 8)
  1438.                 else begin
  1439.                         table[0] := 0;
  1440.                         for i := 1 to 254 do
  1441.                             with cTable[i].RGB do
  1442.                                 table[i] := 255 - trunc(band(bsr(red, 8), 255) * 0.3 + band(bsr(green, 8), 255) * 0.59 + band(bsr(blue, 8), 255) * 0.11);
  1443.                         table[255] := 255;
  1444.                     end;
  1445.             end; {with}
  1446.     end;
  1447.  
  1448.  
  1449.     procedure RedrawLUTWindow;
  1450.     begin
  1451.         LoadLUT(info^.cTable);
  1452.         cheight := 256 + (2 + nExtraColors) * ExtraColorsHeight;
  1453.         SizeWindow(LUTWindow, cwidth, cheight, true);
  1454.         if ScreenDepth <> 8 then
  1455.             DrawLUT;
  1456.     end;
  1457.  
  1458.  
  1459.     procedure DrawDensitySlice (OptionKey: boolean);
  1460.         var
  1461.             i, tRed: integer;
  1462.     begin
  1463.         with info^ do begin
  1464.                 if OptionKey then begin
  1465.                         UndoLutChange;
  1466.                         exit(DrawDensitySlice);
  1467.                     end
  1468.                 else
  1469.                     for i := 0 to 255 do
  1470.                         if (i >= SliceStart) and (i <= SliceEnd) then
  1471.                             cTable[i].rgb := SliceColor
  1472.                         else
  1473.                             ctable[i].rgb := UndoInfo^.cTable[i].rgb;
  1474.                 LoadLUT(cTable);
  1475.                 if ScreenDepth <> 8 then begin
  1476.                         if ScreenDepth > 2 then
  1477.                             DrawLut;
  1478.                         UpdatePicWindow;
  1479.                     end;
  1480.             end;
  1481.     end;
  1482.  
  1483.  
  1484.     procedure SelectLutTool;
  1485.         var
  1486.             tPort: GrafPtr;
  1487.     begin
  1488.         if (CurrentTool <> LutTool) and (CurrentTool <> Wand) then begin
  1489.                 GetPort(tPort);
  1490.                 SetPort(ToolWindow);
  1491.                 InvalRect(ToolRect[CurrentTool]);
  1492.                 InvalRect(ToolRect[LutTool]);
  1493.                 CurrentTool := LutTool;
  1494.                 isSelectionTool := false;
  1495.                 SetPort(tPort);
  1496.             end;
  1497.     end;
  1498.  
  1499.  
  1500.     procedure EnableDensitySlice;
  1501.     begin
  1502.         if not DensitySlicing then begin
  1503.                 SetupLutUndo;
  1504.                 DrawDensitySlice(false);
  1505.                 DensitySlicing := true;
  1506.                 SelectLUTTool;
  1507.             end;
  1508.     end;
  1509.  
  1510.  
  1511.     procedure DoImportLut (fname: str255; vnum: integer);
  1512.         var
  1513.             err: OSErr;
  1514.             f, i,j,tRed: integer;
  1515.             ByteCount: LongInt;
  1516.             ImportedLUT: array[1..3] of packed array[0..255] of byte;
  1517.     begin
  1518.         DisableDensitySlice;
  1519.         err := fsopen(fname, vNum, f);
  1520.         ByteCount := 768;
  1521.         err := fsRead(f, ByteCount, @ImportedLUT);
  1522.         if err = NoErr then
  1523.             with info^ do begin
  1524.                     for i := 0 to 255 do
  1525.                         with cTable[i], cTable[i].rgb do begin
  1526.                                 value := 0;
  1527.                                 red := bsl(band(ImportedLUT[1, i],255), 8);
  1528.                                 green := bsl(band(ImportedLUT[2, i],255), 8);
  1529.                                 blue := bsl(band(ImportedLUT[3, i],255), 8);
  1530.                             end;
  1531.                     LoadLUT(cTable);
  1532.                     SetupPseudocolor;
  1533.                     LutMode := PseudoColor;
  1534.                     IdentityFunction := false;
  1535.                     if isGrayScaleLUT then
  1536.                         info^.LutMode := CustomGrayScale;
  1537.                     UpdateMap;
  1538.                 end
  1539.         else
  1540.             beep;
  1541.         err := fsClose(f);
  1542.     end;
  1543.  
  1544.  
  1545.     procedure OpenOldPalette (fname: str255; RefNum: integer);
  1546. {Opens palette files created by versions NIH Image earlier than 1.42.}
  1547.         var
  1548.             PaletteHeader: ColorArray;
  1549.             err, f, ColorWidth: integer;
  1550.             size: LongInt;
  1551.     begin
  1552.         DisableDensitySlice;
  1553.         err := fsopen(fname, RefNum, f);
  1554.         with info^ do begin
  1555.                 size := SizeOf(ColorArray);
  1556.                 err := fsread(f, size, @PaletteHeader);
  1557.                 nColors := PaletteHeader[0];
  1558.                 if nColors > MaxPseudocolors then
  1559.                     nColors := MaxPseudoColors;
  1560.                 ColorEnd := 255 - PaletteHeader[1];
  1561.                 ColorWidth := PaletteHeader[2];
  1562.                 ColorStart := ColorEnd - nColors * ColorWidth + 1;
  1563.                 if ColorStart < 0 then
  1564.                     ColorStart := 0;
  1565.                 FillColor1 := BlackRGB;
  1566.                 FillColor2 := BlackRGB;
  1567.                 err := fsread(f, size, @RedLut);
  1568.                 err := fsread(f, size, @GreenLut);
  1569.                 err := fsread(f, size, @BlueLut);
  1570.                 LutMode := PseudoColor;
  1571.                 InvertedColorTable := false;
  1572.             end;
  1573.         err := fsclose(f);
  1574.         UpdateLUT;
  1575.     end;
  1576.  
  1577.  
  1578.     procedure OpenNewPalette (fname: str255; RefNum: integer);
  1579. {Opens palette files created by versions of NIH Image later than 1.41.}
  1580.         var
  1581.             err, f: integer;
  1582.             count: LongInt;
  1583.             hdr: PaletteHeader;
  1584.     begin
  1585.         DisableDensitySlice;
  1586.         err := fsopen(fname, RefNum, f);
  1587.         with info^ do begin
  1588.                 count := SizeOf(PaletteHeader);
  1589.                 err := fsread(f, count, @hdr);
  1590.                 with hdr do begin
  1591.                         nColors := pnColors;
  1592.                         if nColors > 256 then
  1593.                             nColors := 256;
  1594.                         ColorStart := pColorStart;
  1595.                         ColorEnd := pColorEnd;
  1596.                         FillColor1 := pFill1;
  1597.                         FillColor2 := pFill2;
  1598.                         InvertedColorTable := false;
  1599.                     end;
  1600.                 count := nColors;
  1601.                 err := fsread(f, count, @RedLut);
  1602.                 count := nColors;
  1603.                 err := fsread(f, count, @GreenLut);
  1604.                 count := nColors;
  1605.                 err := fsread(f, count, @BlueLut);
  1606.                 LutMode := PseudoColor;
  1607.             end;
  1608.         err := fsclose(f);
  1609.         UpdateLUT;
  1610.     end;
  1611.  
  1612.  
  1613.     procedure OpenColorTable (fname: str255; RefNum: integer);
  1614.         var
  1615.             err: OSErr;
  1616.             f: integer;
  1617.             FileSize, count: LongInt;
  1618.             id: packed array[1..4] of char;
  1619.     begin
  1620.         err := fsopen(fname, RefNum, f);
  1621.         err := GetEOF(f, FileSize);
  1622.         count := SizeOf(id);
  1623.         err := fsread(f, count, @id);
  1624.         err := fsclose(f);
  1625.         if FileSize = 768 then
  1626.             DoImportLut(fname, RefNum)
  1627.         else if id = 'ICOL' then
  1628.             OpenNewPalette(fname, RefNum)
  1629.         else
  1630.             OpenOldPalette(fname, RefNum);
  1631.     end;
  1632.  
  1633.  
  1634.     procedure ImportPalette (FileType: OSType; fname: str255; vnum: integer);
  1635.         var
  1636.             RefNum: integer;
  1637.             ok: boolean;
  1638.             err: OSErr;
  1639.     begin
  1640.         err := SetVol(nil, vnum);
  1641.         refNum := OpenResFile(fname);
  1642.         if RefNum <> -1 then begin
  1643.                 if FileType = 'CLUT' then
  1644.                     ok := LoadClutResource(KlutzID)
  1645.                 else
  1646.                     ok := LoadClutResource(PixelPaintID); {Load PixelPaint or Canvas palette}
  1647.                 CloseResFile(RefNum);
  1648.                 if isGrayScaleLUT then begin
  1649.                         info^.LutMode := CustomGrayScale;
  1650.                         DrawMap;
  1651.                     end;
  1652.             end;
  1653.     end;
  1654.  
  1655.  
  1656.     procedure InitPaletteHeader (var hdr: PaletteHeader);
  1657.         var
  1658.             i: integer;
  1659.     begin
  1660.         with hdr, info^ do begin
  1661.                 pID := 'ICOL';
  1662.                 pVersion := version;
  1663.                 pnColors := nColors;
  1664.                 pColorStart := ColorStart;
  1665.                 pColorEnd := ColorEnd;
  1666.                 pFill1 := FillColor1;
  1667.                 pFill2 := FillColor2;
  1668.                 for i := 1 to 4 do
  1669.                     pUnused[i] := 0;
  1670.             end;
  1671.     end;
  1672.  
  1673.  
  1674.     procedure SaveLutResource;
  1675. {Saves the current color table as  a CPAL resource}
  1676.         var
  1677.             id: integer;
  1678.             canceled: boolean;
  1679.             PalH: handle;
  1680.             hdr: PaletteHeader;
  1681.             p: ptr;
  1682.     begin
  1683.         with info^ do begin
  1684.                 id := GetInt('Resource ID', 1000, canceled);
  1685.                 if canceled then
  1686.                     exit(SaveLutResource);
  1687.                 PalH := GetResource('CPAL', id);
  1688.                 if GetHandleSize(PalH) > 0 then begin
  1689.                         RemoveResource(PalH);
  1690.                         DisposeHandle(PalH);
  1691.                     end;
  1692.                 InitPaletteHeader(hdr);
  1693.                 PalH := NewHandle(SizeOF(PaletteHeader) + nColors * 3);
  1694.                 p := PalH^;
  1695.                 BlockMove(@hdr, p, SizeOf(PaletteHeader));
  1696.                 p := ptr(ord4(p) + SizeOf(PaletteHeader));
  1697.                 BlockMove(@RedLut, p, nColors);
  1698.                 p := ptr(ord4(p) + nColors);
  1699.                 BlockMove(@GreenLut, p, nColors);
  1700.                 p := ptr(ord4(p) + nColors);
  1701.                 BlockMove(@BlueLut, p, nColors);
  1702.                 AddResource(PalH, 'CPAL', id, '');
  1703.                 WriteResource(PalH);
  1704.                 if ResError <> NoErr then
  1705.                     beep;
  1706.                 DisposeHandle(PalH);
  1707.             end;
  1708.     end;
  1709.  
  1710.  
  1711.     procedure GetLutResource (id: integer);
  1712.         var
  1713.             LutH: handle;
  1714.             hdr: PaletteHEader;
  1715.             p: ptr;
  1716.     begin
  1717.         with info^ do begin
  1718.                 LutH := GetResource('CPAL', id);
  1719.                 if (ResError <> noErr) or (LutH = nil) then begin
  1720.                         beep;
  1721.                         if LutH <> nil then
  1722.                             ReleaseResource(LutH);
  1723.                         exit(GetLutResource)
  1724.                     end;
  1725.                 p := LutH^;
  1726.                 BlockMove(p, @hdr, SizeOf(PaletteHeader));
  1727.                 with hdr do begin
  1728.                         if pID <> 'ICOL' then begin
  1729.                                 beep;
  1730.                                 ReleaseResource(LutH);
  1731.                                 exit(GetLutResource);
  1732.                             end;
  1733.                         nColors := pnColors;
  1734.                         if nColors > 256 then
  1735.                             nColors := 256;
  1736.                         ColorStart := pColorStart;
  1737.                         ColorEnd := pColorEnd;
  1738.                         FillColor1 := pFill1;
  1739.                         FillColor2 := pFill2;
  1740.                         InvertedColorTable := false;
  1741.                     end;
  1742.                 p := ptr(ord4(p) + SizeOf(PaletteHeader));
  1743.                 BlockMove(p, @RedLut, nColors);
  1744.                 p := ptr(ord4(p) + nColors);
  1745.                 BlockMove(p, @GreenLut, nColors);
  1746.                 p := ptr(ord4(p) + nColors);
  1747.                 BlockMove(p, @BlueLut, nColors);
  1748.                 ReleaseResource(LutH);
  1749.             end;
  1750.     end;
  1751.  
  1752.  
  1753.     procedure DrawScale;
  1754.         var
  1755.             hloc, vloc, width, height, SaveForeground, LUTStart, LutEnd, LUTWidth: integer;
  1756.             SaveGDevice: GDHandle;
  1757.     begin
  1758.         if NoSelection or NotRectangular then
  1759.             exit(DrawScale);
  1760.         ShowWatch;
  1761.         with info^.RoiRect, info^ do begin
  1762.                 width := right - left;
  1763.                 height := bottom - top;
  1764.                 if (width = 0) or (height = 0) then
  1765.                     exit(DrawScale);
  1766.                 SaveGDevice := GetGDevice;
  1767.                 SetGDevice(osGDevice);
  1768.                 SetPort(GrafPtr(osPort));
  1769.                 PenNormal;
  1770.                 SetupUndoFromClip;
  1771.                 SetupUndo;
  1772.                 WhatToUndo := UndoEdit;
  1773.                 SaveForeground := ForegroundIndex;
  1774.                 LUTStart := ColorStart;
  1775.                 if LutStart <= 0 then
  1776.                     LutStart := 1;
  1777.                 LutEnd := ColorEnd;
  1778.                 if LutEnd >= 255 then
  1779.                     LutEnd := 254;
  1780.                 LUTWidth := LutEnd - LutStart + 1;
  1781.                 if width >= height then
  1782.                     for hloc := left to right - 1 do begin
  1783.                             SetForegroundColor(trunc(((hloc - left) / width) * LUTWidth) + LUTStart);
  1784.                             MoveTo(hloc, top);
  1785.                             LineTo(hloc, Bottom - 1);
  1786.                         end
  1787.                 else
  1788.                     for vloc := top to bottom - 1 do begin
  1789.                             SetForegroundColor(trunc(((vloc - top) / height) * LUTWidth) + LUTStart);
  1790.                             MoveTo(left, vloc);
  1791.                             LineTo(right - 1, vloc);
  1792.                         end;
  1793.                 SetForegroundColor(SaveForeground);
  1794.                 changes := true;
  1795.             end;
  1796.         SetupRoiRect;
  1797.         SetGDevice(SaveGDevice);
  1798.     end;
  1799.  
  1800.  
  1801.     procedure MakeSpectrum;
  1802.   {Generates the "Spectrum" color table.}
  1803.         const
  1804.             Sat = -1;
  1805.             Val = -1;
  1806.         var
  1807.             i: integer;
  1808.             color: HSVColor;
  1809.     begin
  1810.         with info^ do begin
  1811.                 for i := 0 to 255 do begin
  1812.                         color.hue := i * 256;
  1813.                         color.saturation := sat;
  1814.                         color.value := val;
  1815.                         HSV2RGB(color, ctable[i].rgb);
  1816.                     end;
  1817.                 LutMode := ColorLut;
  1818.                 IdentityFunction := false;
  1819.                 SetupPseudocolor;
  1820.             end;
  1821.     end;
  1822.  
  1823.  
  1824.     function GetColorTableItem (ctab: ColorTableType): integer;
  1825.     begin
  1826.         case ctab of
  1827.             AppleDefault: 
  1828.                 GetColorTableItem := SystemPaletteItem;
  1829.             Pseudo20: 
  1830.                 GetColorTableItem := Pseudo20Item;
  1831.             Pseudo32: 
  1832.                 GetColorTableItem := Pseudo32Item;
  1833.             Rainbow: 
  1834.                 GetColorTableItem := RainbowItem;
  1835.             Fire1: 
  1836.                 GetColorTableItem := Fire1Item;
  1837.             Fire2: 
  1838.                 GetColorTableItem := Fire2Item;
  1839.             Ice: 
  1840.                 GetColorTableItem := IceItem;
  1841.             Grays: 
  1842.                 GetColorTableItem := GraysItem;
  1843.             Spectrum: 
  1844.                 GetColorTableItem := SpectrumItem;
  1845.             otherwise
  1846.                 GetColorTableItem := Pseudo20Item;
  1847.         end;
  1848.     end;
  1849.  
  1850.  
  1851.     procedure SwitchColorTables (item: integer; update: boolean);
  1852.         var
  1853.             ok: boolean;
  1854.     begin
  1855.         DisableDensitySlice;
  1856.         if update then
  1857.             SetupLutUndo;
  1858.         with info^ do begin
  1859.                 case item of
  1860.                     SystemPaletteItem:  begin
  1861.                             ok := LoadCLUTResource(AppleDefaultCLUT);
  1862.                             ColorTable := AppleDefault;
  1863.                         end;
  1864.                     Pseudo20Item:  begin
  1865.                             GetLutResource(Pseudo20ID);
  1866.                             ColorTable := Pseudo20;
  1867.                         end;
  1868.                     Pseudo32Item:  begin
  1869.                             GetLutResource(Pseudo32ID);
  1870.                             ColorTable := Pseudo32;
  1871.                         end;
  1872.                     RainbowItem:  begin
  1873.                             GetLutResource(RainbowID);
  1874.                             ColorTable := Rainbow;
  1875.                         end;
  1876.                     Fire1Item:  begin
  1877.                             GetLutResource(Fire1ID);
  1878.                             ColorTable := Fire1;
  1879.                         end;
  1880.                     Fire2Item:  begin
  1881.                             GetLutResource(Fire2ID);
  1882.                             ColorTable := Fire2;
  1883.                         end;
  1884.                     IceItem:  begin
  1885.                             GetLutResource(IceID);
  1886.                             ColorTable := Ice;
  1887.                         end;
  1888.                     GraysItem:  begin
  1889.                             GetLutResource(GraysID);
  1890.                             ColorTable := Grays;
  1891.                         end;
  1892.                     SpectrumItem: 
  1893.                         if ControlKeyDown and OptionKeyDown and ShiftKeyDown then
  1894.                             SaveLutResource
  1895.                         else begin
  1896.                                 MakeSpectrum;
  1897.                                 ColorTable := Spectrum;
  1898.                             end;
  1899.                 end; {case}
  1900.                 LutMode := Pseudocolor;
  1901.                 if update then begin
  1902.                         UpdateLUT;
  1903.                         UpdateMap;
  1904.                     end;
  1905.             end;
  1906.     end;
  1907.  
  1908.  
  1909.     procedure SetNumberOfColors (n: integer);
  1910.         var
  1911.             i, r, g, b, index: integer;
  1912.             eIndex, inc, fraction: extended;
  1913.             SaveRed, SaveGreen, SaveBlue: LutArray;
  1914.     begin
  1915.         with info^ do begin
  1916.                 SaveRed := RedLUT;
  1917.                 SaveGreen := GreenLUT;
  1918.                 SaveBlue := BlueLUT;
  1919.                 eIndex := 0.0;
  1920.                 inc := (nColors - 1) / (n - 1);
  1921.                 for i := 0 to n - 1 do begin
  1922.                         index := trunc(eIndex);
  1923.                         if index >= (nColors - 1) then begin
  1924.                                 RedLUT[i] := SaveRed[index];
  1925.                                 GreenLUT[i] := SaveGreen[index];
  1926.                                 BlueLUT[i] := SaveBlue[index]
  1927.                             end
  1928.                         else begin
  1929.                                 fraction := eIndex - index;
  1930.                                 RedLUT[i] := round(SaveRed[index] * (1.0 - fraction) + SaveRed[index + 1] * fraction);
  1931.                                 GreenLUT[i] := round(SaveGreen[index] * (1.0 - fraction) + SaveGreen[index + 1] * fraction);
  1932.                                 BlueLUT[i] := round(SaveBlue[index] * (1.0 - fraction) + SaveBlue[index + 1] * fraction);
  1933.                             end;
  1934.                         eIndex := eIndex + inc;
  1935.                     end;
  1936.                 nColors := n;
  1937.                 LutMode := PseudoColor;
  1938.                 ColorTable := CustomTable;
  1939.                 UpdateLUT;
  1940.                 UpdateMap;
  1941.             end;
  1942.     end;
  1943.  
  1944.  
  1945.     procedure SetNumberOfExtraColors;
  1946.         var
  1947.             n: integer;
  1948.             Canceled: boolean;
  1949.     begin
  1950.         n := GetInt('Number of Extra Colors(0..6):', nExtraColors, Canceled);
  1951.         if (n <= 6) and (n >= 0) and not Canceled then begin
  1952.                 nExtraColors := n;
  1953.                 RedrawLUTWindow;
  1954.                 SelectWindow(LUTWindow);
  1955.                 if info <> NoInfo then
  1956.                     SelectWindow(info^.wptr);
  1957.             end
  1958.         else if not Canceled then
  1959.             beep;
  1960.     end;
  1961.  
  1962.  
  1963.     procedure DoLutOptions;
  1964.         const
  1965.             nColorsID = 7;
  1966.             nExtraColorsID = 8;
  1967.             InvertID = 9;
  1968.         var
  1969.             mylog: DialogPtr;
  1970.             item, i, n, nExtra: integer;
  1971.             InvertLut: boolean;
  1972.     begin
  1973.         with info^ do begin
  1974.                 InitCursor;
  1975.                 mylog := GetNewDialog(210, nil, pointer(-1));
  1976.                 n := nColors;
  1977.                 SetDNum(MyLog, nColorsID, n);
  1978.                 nExtra := nExtraColors;
  1979.                 SetDNum(MyLog, nExtraColorsID, nExtra);
  1980.                 InvertLut := false;
  1981.                 SetDlogItem(mylog, InvertID, ord(InvertLut));
  1982.                 repeat
  1983.                     ModalDialog(nil, item);
  1984.                     if item = nColorsID then
  1985.                         n := GetDNum(MyLog, nColorsID);
  1986.                     if item = nExtraColorsID then
  1987.                         nExtra := GetDNum(MyLog, nExtraColorsID);
  1988.                     if item = InvertID then begin
  1989.                             InvertLut := not InvertLut;
  1990.                             SetDlogItem(mylog, InvertID, ord(InvertLut));
  1991.                         end;
  1992.                 until (item = ok) or (item = cancel);
  1993.                 DisposeDialog(mylog);
  1994.                 if item = cancel then
  1995.                     exit(DoLutOptions);
  1996.                 DisableDensitySlice;
  1997.                 SetupLutUndo;
  1998.                 if n < 1 then
  1999.                     n := 1;
  2000.                 if n > 256 then
  2001.                     n := 256;
  2002.                 if n <> nColors then
  2003.                     SetNumberOfColors(n);
  2004.                 if (nExtra <> nExtraColors) and (nExtra >= 0) and (nExtra <= 6) then begin
  2005.                         nExtraColors := nExtra;
  2006.                         RedrawLUTWindow;
  2007.                         SelectWindow(LUTWindow);
  2008.                         if info <> NoInfo then
  2009.                             SelectWindow(info^.wptr);
  2010.                     end;
  2011.                 if InvertLut then begin
  2012.                         InvertPalette;
  2013.                         UpdateLut;
  2014.                         if ScreenDepth <> 8 then
  2015.                             DrawLUT;
  2016.                     end;
  2017.             end; {with info}
  2018.     end;
  2019.  
  2020.  
  2021.     function SetupMask: boolean;
  2022. {Creates a mask in the undo buffer for operating}
  2023. {on non-rectangular selections .}
  2024.         var
  2025.             tPort: GrafPtr;
  2026.             SaveInfo: InfoPtr;
  2027.             SaveGDevice: GDHandle;
  2028.     begin
  2029.         if NoUndo then begin
  2030.                 SetupMask := false;
  2031.                 exit(SetupMask)
  2032.             end;
  2033.         SetupUndoInfoRec;
  2034.         SaveInfo := Info;
  2035.         Info := UndoInfo;
  2036.         SaveGDevice := GetGDevice;
  2037.         SetGDevice(osGDevice);
  2038.         GetPort(tPort);
  2039.         with Info^ do begin
  2040.                 SetPort(GrafPtr(osPort));
  2041.                 pmForeColor(BlackIndex);
  2042.                 pmBackColor(WhiteIndex);
  2043.                 PenNormal;
  2044.                 EraseRect(RoiRect);
  2045.                 PaintRgn(roiRgn);
  2046.             end;
  2047.         SetPort(tPort);
  2048.         SetGDevice(SaveGDevice);
  2049.         Info := SaveInfo;
  2050.         SetupMask := true;
  2051.     end;
  2052.  
  2053.     procedure ApplyTableToLine (data: ptr; var table: LookupTable; width: LongInt);
  2054. {$IFC PowerPC}
  2055.     var
  2056.         line: LinePtr;
  2057.         i: integer;
  2058.     begin
  2059.         line := LinePtr(data);
  2060.         for i := 0 to width - 1 do
  2061.             Line^[i] := table[band(Line^[i],255)];
  2062.     end;
  2063. {$ELSEC}
  2064.  
  2065. {a0 = data}
  2066. {a1 = lookup table}
  2067. {d0 = width }
  2068. {d1 = pixel value}
  2069. inline
  2070.     $4E56, $0000, {  link a6,#0}
  2071.     $48E7, $C0C0, {  movem.l a0-a1/d0-d1,-(sp)}
  2072.     $206E, $000C, {  move.l 12(a6),a0}
  2073.     $226E, $0008, {  move.l 8(a6),a1}
  2074.     $202E, $0004, {  move.l 4(a6),d0}
  2075.     $5380,       {  subq.l #1,d0}
  2076.     $4281,       {  clr.l d1}
  2077.     $1210,       {L move.b (a0),d1}
  2078.     $10F1, $1000, {  move.b 0(a1,d1.w),(a0)+}
  2079.     $51C8, $FFF8, {  dbra d0,L}
  2080.     $4CDF, $0303, {  movem.l (sp)+,a0-a1/d0-d1}
  2081.     $4E5E,       {  unlk a6}
  2082.     $DEFC, $000C; {  add.w #12,sp}
  2083. {$ENDC}
  2084.  
  2085.  
  2086. procedure PutLineUsingMask (h, v, count: integer; var line: LineType);
  2087.     var
  2088.         aLine, MaskLine: LineType;
  2089.         i: integer;
  2090.         SaveInfo: InfoPtr;
  2091. begin
  2092.     if count > MaxLine then
  2093.         count := MaxLine;
  2094.     GetLine(h, v, count, aline);
  2095.     SaveInfo := Info;
  2096.     Info := UndoInfo;
  2097.     GetLine(h, v, count, MaskLine);
  2098.     for i := 0 to count - 1 do
  2099.         if MaskLine[i] = BlackIndex then
  2100.             aLine[i] := line[i];
  2101.     info := SaveInfo;
  2102.     PutLine(h, v, count, aLine);
  2103. end;
  2104.  
  2105.  
  2106. procedure ApplyTable(var table: LookupTable);
  2107.     var
  2108.         width, NumberOfLines, i, hloc, vloc: integer;
  2109.         offset: LongInt;
  2110.         p: ptr;
  2111.         UseMask: boolean;
  2112.         TempLine: LineType;
  2113.         AutoSelectAll: boolean;
  2114. begin
  2115.     if NotInBounds then
  2116.         exit(ApplyTable);
  2117.     AutoSelectAll := not Info^.RoiShowing;
  2118.     if AutoSelectAll then
  2119.         SelectAll(false);
  2120.     if TooWide then
  2121.         exit(ApplyTable);
  2122.     ShowWatch;
  2123.     with info^.RoiRect, info^ do begin
  2124.             if RoiType <> RectRoi then
  2125.                 UseMask := SetupMask
  2126.             else
  2127.                 UseMask := false;
  2128.             SetupUndoFromClip;
  2129.             WhatToUndo := UndoTransform;
  2130.             offset := top * BytesPerRow + left;
  2131.             if UseMask then
  2132.                 p := @TempLine
  2133.             else
  2134.                 p := ptr(ord4(PicBaseAddr) + offset);
  2135.             width := right - left;
  2136.             NumberOfLines := bottom - top;
  2137.             hloc := left;
  2138.             vloc := top;
  2139.         end;
  2140.     if width > 0 then
  2141.         for i := 1 to NumberOfLines do
  2142.             if UseMask then begin
  2143.                     GetLine(hloc, vloc, width, TempLine);
  2144.                     ApplyTableToLine(p, table, width);
  2145.                     PutLineUsingMask(hloc, vloc, width, TempLine);
  2146.                     vloc := vloc + 1
  2147.                 end
  2148.             else begin
  2149.                     ApplyTableToLine(p, table, width);
  2150.                     p := ptr(ord4(p) + info^.BytesPerRow);
  2151.                 end;
  2152.     with info^ do begin
  2153.             UpdateScreen(RoiRect);
  2154.             Info^.changes := true;
  2155.         end;
  2156.     SetupRoiRect;
  2157.     if AutoSelectAll then
  2158.         KillRoi;
  2159. end;
  2160.  
  2161.  
  2162. procedure FixColors;
  2163.     {Because NIH Image always sets LUT entries 0 and 255 to white and black respectively we need to map}
  2164.     {pixels with values of 0 or 255 to the nearest matching color in the other 254  LUT entries.}
  2165.     var
  2166.         i, match0, match255: integer;
  2167.         table: LookupTable;
  2168.  
  2169.     procedure BestMatch (index1: integer; var match: integer);
  2170.         var
  2171.             i, index2: integer;
  2172.             rdiff, gdiff, bdiff, r1, g1, b1: LongInt;
  2173.             diff, mindiff: extended;
  2174.     begin
  2175.         match := index1;
  2176.         mindiff := 10e10;
  2177.         if index1 = 0 then
  2178.             index2 := 1
  2179.         else
  2180.             index2 := 254;
  2181.         with info^ do begin
  2182.             r1:=band(bsr(cTable[index1].rgb.red, 8),255);
  2183.             g1:=band(bsr(cTable[index1].rgb.green, 8),255);
  2184.             b1:=band(bsr(cTable[index1].rgb.blue, 8),255);
  2185.             for i := 1 to 254 do begin
  2186.                     rdiff := r1 - band(bsr(cTable[index2].rgb.red, 8),255);
  2187.                     gdiff := g1 - band(bsr(cTable[index2].rgb.green, 8),255);
  2188.                     bdiff := b1 - band(bsr(cTable[index2].rgb.blue, 8),255);
  2189.                     diff := sqrt(sqr(rdiff) + sqr(gdiff) + sqr(bdiff));
  2190.                     if diff < mindiff then begin
  2191.                             match := index2;
  2192.                             mindiff := diff;
  2193.                         end;
  2194.                     if index1 = 0 then
  2195.                         index2 := index2 + 1
  2196.                     else
  2197.                         index2 := index2 - 1;
  2198.                 end; {for}
  2199.         end; {with}
  2200.     end;
  2201.  
  2202. begin
  2203.     BestMatch(0, match0);
  2204.     BestMatch(255, match255);
  2205.     table[0] := match0;
  2206.     for i := 1 to 254 do
  2207.         table[i] := i;
  2208.     table[255] := match255;
  2209.     ApplyTable(table);
  2210. end;
  2211.  
  2212.  
  2213. end.